#include "StdAfx.h"
#include "vtextedit.h"

namespace
{
	const QString rsrcPath = ":/Resources/Icons_se";
}

//////////////////////////////////////////////////////////////////////////
// Multi-line editor
VMultilineEdit::VMultilineEdit(QWidget* parent) 
	:	VFlowLayoutTextEdit(parent)
	, fitted_height(0)
	, m_ignoreInput(false)
{
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	//this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

	setTabChangesFocus(true);

	//connect(this, SIGNAL(textChanged()), this, SLOT(textChange()));
}

void VMultilineEdit::focusInEvent(QFocusEvent *e)
{
	if (e->gotFocus())
		emit editingStarted();

	QTextEdit::focusInEvent(e);
}

void VMultilineEdit::focusOutEvent(QFocusEvent *e)
{
	if (e->lostFocus())
		emit editingFinished();

	QTextEdit::focusOutEvent(e);
}

/*void VMultilineEdit::textChange()
{
	/*QFontInfo fi = fontInfo();
	QSize document_size(document()->documentLayout()->documentSize().toSize());
	this->fitted_height = document_size.height();

	if (fitted_height == 0)
	{
	fitted_height = fi.pixelSize();
	fitted_height += document()->documentMargin()*4;
	}
	else
	fitted_height += document()->documentMargin();

	this->updateGeometry();* /
}*/

//////////////////////////////////////////////////////////////////////////
// VMultilineEditHelper
VMultilineEditHelper::VMultilineEditHelper(VMultilineEdit* editor, QObject* parent)
	: QObject(parent)
	, textEdit(editor)
{
	setupTextActions();

	connect(textEdit, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
		this, SLOT(currentCharFormatChanged(QTextCharFormat)));
	connect(textEdit, SIGNAL(cursorPositionChanged()),
		this, SLOT(cursorPositionChanged()));

	fontChanged(textEdit->font());
	colorChanged(textEdit->textColor());
	alignmentChanged(textEdit->alignment());

	connect(textEdit, SIGNAL(editingStarted()), this, SLOT(editorGotFocus()));
	connect(textEdit, SIGNAL(editingFinished()), this, SLOT(editorLostFocus()));
	//connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(focusChange(QWidget*, QWidget*)));
}

void VMultilineEditHelper::setupTextActions()
{
	tb = new QToolBar;//(qobject_cast<QWidget*>(textEdit->parent()));
	tb->setWindowTitle(tr("Format Actions"));
	tb->setWindowFlags(Qt::Tool | Qt::MSWindowsFixedSizeDialogHint /*| Qt::WindowTitleHint*/	| Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint);
	//tb->setFocusPolicy(Qt::NoFocus);

	actionTextBold = new QAction(QIcon::fromTheme("format-text-bold", QIcon(rsrcPath + "/textbold.png")),
		tr("&Bold"), this);
	actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B);
	actionTextBold->setPriority(QAction::LowPriority);
	QFont bold;
	bold.setBold(true);
	actionTextBold->setFont(bold);
	connect(actionTextBold, SIGNAL(triggered()), this, SLOT(textBold()));
	tb->addAction(actionTextBold);		
	actionTextBold->setCheckable(true);

	actionTextItalic = new QAction(QIcon::fromTheme("format-text-italic", QIcon(rsrcPath + "/textitalic.png")),
		tr("&Italic"), this);
	actionTextItalic->setPriority(QAction::LowPriority);
	actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I);
	QFont italic;
	italic.setItalic(true);
	actionTextItalic->setFont(italic);
	connect(actionTextItalic, SIGNAL(triggered()), this, SLOT(textItalic()));
	tb->addAction(actionTextItalic);
	actionTextItalic->setCheckable(true);

	actionTextUnderline = new QAction(QIcon::fromTheme("format-text-underline", QIcon(rsrcPath + "/textunder.png")),
		tr("&Underline"), this);
	actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U);
	actionTextUnderline->setPriority(QAction::LowPriority);
	QFont underline;
	underline.setUnderline(true);
	actionTextUnderline->setFont(underline);
	connect(actionTextUnderline, SIGNAL(triggered()), this, SLOT(textUnderline()));
	tb->addAction(actionTextUnderline);
	actionTextUnderline->setCheckable(true);

	QActionGroup *grp = new QActionGroup(this);
	connect(grp, SIGNAL(triggered(QAction*)), this, SLOT(textAlign(QAction*)));

	// Make sure the alignLeft  is always left of the alignRight
	if (QApplication::isLeftToRight()) {
		actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")),
			tr("&Left"), grp);
		actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp);
		actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp);
	} else {
		actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp);
		actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp);
		actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")), tr("&Left"), grp);
	}
	actionAlignJustify = new QAction(QIcon::fromTheme("format-justify-fill", QIcon(rsrcPath + "/textjustify.png")), tr("&Justify"), grp);

	actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
	actionAlignLeft->setCheckable(true);
	actionAlignLeft->setPriority(QAction::LowPriority);
	actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
	actionAlignCenter->setCheckable(true);
	actionAlignCenter->setPriority(QAction::LowPriority);
	actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
	actionAlignRight->setCheckable(true);
	actionAlignRight->setPriority(QAction::LowPriority);
	actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
	actionAlignJustify->setCheckable(true);
	actionAlignJustify->setPriority(QAction::LowPriority);

	tb->addActions(grp->actions());

	QPixmap pix(16, 16);
	pix.fill(Qt::black);
	actionTextColor = new QAction(pix, tr("&Color..."), this);
	connect(actionTextColor, SIGNAL(triggered()), this, SLOT(textColor()));
	tb->addAction(actionTextColor);

	tb->addSeparator();

	comboStyle = new QComboBox(tb);
	tb->addWidget(comboStyle);
	comboStyle->addItem("Standard");
	comboStyle->addItem("Bullet List (Disc)");
	comboStyle->addItem("Bullet List (Circle)");
	comboStyle->addItem("Bullet List (Square)");
	comboStyle->addItem("Ordered List (Decimal)");
	comboStyle->addItem("Ordered List (Alpha lower)");
	comboStyle->addItem("Ordered List (Alpha upper)");
	comboStyle->addItem("Ordered List (Roman lower)");
	comboStyle->addItem("Ordered List (Roman upper)");
	connect(comboStyle, SIGNAL(activated(int)),
		this, SLOT(textStyle(int)));

	comboFont = new QFontComboBox(tb);
	tb->addWidget(comboFont);
	connect(comboFont, SIGNAL(activated(QString)),
		this, SLOT(textFamily(QString)));

	comboSize = new QComboBox(tb);
	comboSize->setObjectName("comboSize");
	tb->addWidget(comboSize);
	comboSize->setEditable(true);

	QFontDatabase db;
	foreach(int size, db.standardSizes())
		comboSize->addItem(QString::number(size));

	connect(comboSize, SIGNAL(activated(QString)),
		this, SLOT(textSize(QString)));
	comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font()
		.pointSize())));
}

void VMultilineEditHelper::focusChange(QWidget* old, QWidget* now)
{
	if (old == textEdit && (now && now->parent() != tb))
		tb->hide();

	//if (now && now->parent() != tb && now !=textEdit)
	//	tb->hide();

	if (!now)
		tb->hide();
}

void VMultilineEditHelper::editorGotFocus()
{
	//tb->show();
	//textEdit->setFocus();

	QRect rtb(tb->geometry());
	int w = rtb.width();
	int h = rtb.height();
	QPoint poste(textEdit->mapToGlobal(textEdit->pos()));
	//QPoint poste(textEdit->pos());	
	//tb->setGeometry(poste.x()-20, poste.y()-h-20, w, h);
	//qDebug() << poste << textEdit->pos() << textEdit->size().height() << tb->geometry();
}

void VMultilineEditHelper::editorLostFocus()
{
	//qDebug() << textEdit->toPlainText() << "lost focus";
	//if (tb)
	//	tb->hide();
}

void VMultilineEditHelper::textBold()
{
	QTextCharFormat fmt;
	fmt.setFontWeight(actionTextBold->isChecked() ? QFont::Bold : QFont::Normal);
	mergeFormatOnWordOrSelection(fmt);
}

void VMultilineEditHelper::textUnderline()
{
	QTextCharFormat fmt;
	fmt.setFontUnderline(actionTextUnderline->isChecked());
	mergeFormatOnWordOrSelection(fmt);
}

void VMultilineEditHelper::textItalic()
{
	QTextCharFormat fmt;
	fmt.setFontItalic(actionTextItalic->isChecked());
	mergeFormatOnWordOrSelection(fmt);
}

void VMultilineEditHelper::textFamily(const QString &f)
{
	QTextCharFormat fmt;
	fmt.setFontFamily(f);
	mergeFormatOnWordOrSelection(fmt);
}

void VMultilineEditHelper::textSize(const QString &p)
{
	qreal pointSize = p.toFloat();
	if (p.toFloat() > 0) {
		QTextCharFormat fmt;
		fmt.setFontPointSize(pointSize);
		mergeFormatOnWordOrSelection(fmt);
	}
}

void VMultilineEditHelper::textStyle(int styleIndex)
{
	QTextCursor cursor = textEdit->textCursor();

	if (styleIndex != 0) {
		QTextListFormat::Style style = QTextListFormat::ListDisc;

		switch (styleIndex) {
			default:
			case 1:
				style = QTextListFormat::ListDisc;
				break;
			case 2:
				style = QTextListFormat::ListCircle;
				break;
			case 3:
				style = QTextListFormat::ListSquare;
				break;
			case 4:
				style = QTextListFormat::ListDecimal;
				break;
			case 5:
				style = QTextListFormat::ListLowerAlpha;
				break;
			case 6:
				style = QTextListFormat::ListUpperAlpha;
				break;
			case 7:
				style = QTextListFormat::ListLowerRoman;
				break;
			case 8:
				style = QTextListFormat::ListUpperRoman;
				break;
		}

		cursor.beginEditBlock();

		QTextBlockFormat blockFmt = cursor.blockFormat();

		QTextListFormat listFmt;

		if (cursor.currentList()) {
			listFmt = cursor.currentList()->format();
		} else {
			listFmt.setIndent(blockFmt.indent() + 1);
			blockFmt.setIndent(0);
			cursor.setBlockFormat(blockFmt);
		}

		listFmt.setStyle(style);

		cursor.createList(listFmt);

		cursor.endEditBlock();
	} else {
		// ####
		QTextBlockFormat bfmt;
		bfmt.setObjectIndex(-1);
		cursor.mergeBlockFormat(bfmt);
	}
}

void VMultilineEditHelper::textColor()
{
	QColor col = QColorDialog::getColor(textEdit->textColor());
	if (!col.isValid())
		return;
	QTextCharFormat fmt;
	fmt.setForeground(col);
	mergeFormatOnWordOrSelection(fmt);
	colorChanged(col);
}

void VMultilineEditHelper::textAlign(QAction *a)
{
	if (a == actionAlignLeft)
		textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
	else if (a == actionAlignCenter)
		textEdit->setAlignment(Qt::AlignHCenter);
	else if (a == actionAlignRight)
		textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute);
	else if (a == actionAlignJustify)
		textEdit->setAlignment(Qt::AlignJustify);
}

void VMultilineEditHelper::currentCharFormatChanged(const QTextCharFormat &format)
{
	fontChanged(format.font());
	colorChanged(format.foreground().color());
}

void VMultilineEditHelper::cursorPositionChanged()
{
	alignmentChanged(textEdit->alignment());
}

void VMultilineEditHelper::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
	QTextCursor cursor = textEdit->textCursor();
	if (!cursor.hasSelection())
		cursor.select(QTextCursor::WordUnderCursor);
	cursor.mergeCharFormat(format);
	textEdit->mergeCurrentCharFormat(format);
}

void VMultilineEditHelper::fontChanged(const QFont &f)
{
	comboFont->setCurrentIndex(comboFont->findText(QFontInfo(f).family()));
	comboSize->setCurrentIndex(comboSize->findText(QString::number(f.pointSize())));
	actionTextBold->setChecked(f.bold());
	actionTextItalic->setChecked(f.italic());
	actionTextUnderline->setChecked(f.underline());
}

void VMultilineEditHelper::colorChanged(const QColor &c)
{
	QPixmap pix(16, 16);
	pix.fill(c);
	actionTextColor->setIcon(pix);
}

void VMultilineEditHelper::alignmentChanged(Qt::Alignment a)
{
	if (a & Qt::AlignLeft) {
		actionAlignLeft->setChecked(true);
	} else if (a & Qt::AlignHCenter) {
		actionAlignCenter->setChecked(true);
	} else if (a & Qt::AlignRight) {
		actionAlignRight->setChecked(true);
	} else if (a & Qt::AlignJustify) {
		actionAlignJustify->setChecked(true);
	}
}